<template>
  <el-button
    v-show="btnShow"
    :title="title"
    :type="btnType"
    :disabled="disabled"
    :round="styles.round"
    :circle="styles.circle"
    :link="styles.link"
    size="default"
    :style="{
      '--bgColor': btnColor,
      '--bdColor': btnColor,
      '--hoverColor': styles.hoverColor,
      'font-size': styles.fontSize ? styles.fontSize + 'px' : undefined,
      color: styles.textColor
    }"
    :class="{
      'anvil-code-custom-button': true,
      'custom-btn-bg': !styles.link && btnColor,
      'custom-btn-hover': !styles.link && styles.hoverColor,
      'custom-btn-text-bg': styles.link && btnColor,
      'custom-btn-text-hover': styles.link && styles.hoverColor
    }"
    v-hasPermi="permission"
    @click="btnClick"
  >
    <template #icon v-if="styles.icon || styles.businessIcon">
      <component v-if="styles.icon" :is="styles.icon" />
      <svg-icon v-else-if="styles.businessIcon" :icon-class="styles.businessIcon" />
    </template>
    <template v-if="buttonName">
      {{ modelValue ? modelValue : buttonName }}
    </template>
  </el-button>

  <el-dialog v-model="visible" append-to-body class="anvil-code-confirm" width="400px">
    <template #header>
      <div class="anvil-code-confirm-header"> 提示 </div>
    </template>
    <div class="anvil-code-confirm-body">
      <div class="confirm-content">
        <el-icon v-if="confirmSetting.icon" :color="confirmSetting.iconColor" :size="confirmSetting.iconSize">
          <component :is="confirmSetting.icon" />
        </el-icon>
        <svg-icon v-else-if="confirmSetting.businessIcon" :icon-class="confirmSetting.businessIcon" :color="confirmSetting.iconColor" :size="confirmSetting.iconSize" />
        <div>
          {{ confirmSetting.text }}
        </div>
      </div>
    </div>
    <template #footer>
      <div class="anvil-code-confirm-footer">
        <el-button type="primary" class="anvil-code-custom-button anvil-code-pirmary-btn" @click="handleConfirm">确定</el-button>
        <el-button class="anvil-code-custom-button anvil-code-pirmary-btn" @click="handleCancel">取消</el-button>
      </div>
    </template>
  </el-dialog>
  <select-next-user v-if="showSelectUser" :visible="showSelectUser" :selectUserParam="selectUserParams" @selected="doSelected" @close="showSelectUser = false" />
</template>
<script>
import { Base64 } from 'js-base64';
import { ElMessage, ElMessageBox } from 'element-plus';
import qs from 'qs';
import { useAnvilCodeStore } from '../../store/modules/code';
import JsonPath from 'jsonpath';
import { cloneDeep, flattenDeep } from 'lodash-es';
import { startWfInstanceAndSelectUser, startWfInstanceWithoutModel, startWfInstance } from '../../api/wf';
import {
  customApiExecute,
  modelApiExecute,
  handleGetSerialNumber,
  localApiExecute,
  getFormDataWithScope,
  getParamsWithMerge,
  executeFunctionsInOrderByParamsSetting,
  getDisplayRule
} from '../../utils/common-methods';
import SelectNextUser from '@/components/Zmids/Workflow/SelectNextUser.vue';

export default {
  name: 'CustomButton',
  components: { SelectNextUser },
  inheritAttrs: false,
  props: {
    modelValue: {
      type: String,
      default: ''
    },
    optionColumn: {
      type: Array,
      default: () => []
    },
    buttonName: {
      type: String,
      default: ''
    },
    styles: {
      type: Object,
      default: () => {}
    },
    feature: {
      type: Object,
      default: () => {}
    },
    disabled: {
      type: Boolean,
      default: false
    },
    formData: {
      type: Object,
      default: () => {}
    },
    position: {
      type: String,
      default: ''
    },
    clickBanned: {
      type: Boolean,
      default: false
    },
    // 列数据传递过来的参数
    scopeRow: {
      type: Object,
      default: () => {}
    },
    isShowByRules: {
      type: Boolean,
      default: false
    },
    displayRules: {
      type: Array,
      default: () => []
    },
    confirm: {
      type: Boolean,
      default: false
    },
    confirmSetting: {
      type: Object,
      default: () => {}
    },
    // 同html标签title作用
    title: {
      type: String,
      default: ''
    },
    // 权限控制
    permission: {
      type: Array,
      default: () => []
    },
    // 是否开启表单校验
    validate: {
      type: Boolean,
      default: false
    },
    // 选中的数据校验规则
    validateRules: {
      type: Array,
      default: () => []
    },
    // 是否开启表单校验失败后显示错误信息
    validateShowFail: {
      type: Boolean,
      default: false
    },
    // 校验失败后显示的错误信息
    validateFailText: {
      type: String,
      default: '校验失败！'
    }
  },
  data() {
    return {
      visible: false,
      // curBtnFunc: undefined,
      showSelectUser: false,
      selectUserParams: {}
    };
  },
  computed: {
    btnType() {
      if (this.position && this.position == 'inner') {
        return 'text';
      }
      if (this.styles && this.styles.type) {
        return this.styles.type;
      } else {
        return 'primary';
      }
    },
    btnIcon() {
      if (this.styles && this.styles.icon) {
        return this.styles.icon;
      } else {
        return '';
      }
    },
    btnColor() {
      if (this.position && this.position == 'inner') {
        return '';
      }
      if (this.styles && this.styles.color) {
        return this.styles.color;
      } else {
        return '';
      }
    },
    // 控制按钮显隐
    btnShow: {
      get() {
        try {
          let res = true;
          if (!this.formData) {
            return res;
          }
          if (this.isShowByRules && this.displayRules) {
            // 用全局变量记录表单值
            const windowVars = [];
            for (let key in this.formData) {
              window[key] = this.formData[key];
              windowVars.push(key);
            }
            if (this.scopeRow && this.scopeRow.row) {
              window.row = this.scopeRow.row;
              windowVars.push('row');
            }
            const rootRule = this.displayRules[0];
            const rule = getDisplayRule(rootRule);
            console.log('当前按钮显隐规则为', rule);
            res = eval(rule);
            console.log('当前按钮显隐规则判断结果为', res);
            console.log('目前的全局变量', windowVars);
            windowVars.map((v) => {
              delete window[v];
            });
          }
          return res;
        } catch (e) {
          console.log('btnShow get Error!', e);
          return true;
        }
      },
      set(val) {
        this.btnShow = val;
      }
    }
  },
  watch: {
    formData: {
      handler() {},
      deep: true,
      immediate: true
    },
    scopeRow: {
      handler() {},
      deep: true
    }
  },
  methods: {
    // 按钮自己的点击功能,如果自定义按钮在列表页，存在传参，
    async btnClick() {
      if (!this.clickBanned) {
        if (this.confirm) {
          this.handleFormValidate(() => {
            this.visible = true;
          });
        } else {
          await this.beforeBtnFunc();
          this.handleFormValidate(this.btnFunc);
        }
      }
      this.$emit('custom-click');
    },
    async handleConfirm() {
      await this.beforeBtnFunc();
      this.btnFunc();
      this.handleCancel();
    },
    handleCancel() {
      this.visible = false;
    },
    // 在按钮点击之前执行的钩子
    async beforeBtnFunc() {
      await handleGetSerialNumber(this.optionColumn, this.formData);
    },
    // 按钮点击时校验表单数据
    async handleFormValidate(callback) {
      if (!this.validate) {
        callback();
        return;
      }
      const anvilCodeStore = useAnvilCodeStore();
      // 获取当前主表单实例
      const instance = anvilCodeStore.getInstance('', 'form', this.$attrs.pageId);
      // 规则解析并存储
      let dynamicRulesMap = {},
        mainFormRules = undefined;
      if (this.validateRules && this.validateRules.length) {
        // 区分主表单与子表单的校验规则功能
        mainFormRules = this.validateRules.filter((rule) => !rule.includes('_'));
        // 获取子表单校验规则
        const dynamicFormRules = this.validateRules.filter((rule) => rule.includes('_'));
        dynamicFormRules.map(async (rule) => {
          // 根据rule拼接规则解析为 规则组件类型-规则组件id-规则id
          const [compType, compUuid, ruleUuid] = rule.split('_');
          if (compType == 'anvilDynamic') {
            if (!dynamicRulesMap[compUuid]) {
              dynamicRulesMap[compUuid] = [ruleUuid];
            } else {
              dynamicRulesMap[compUuid].push(ruleUuid);
            }
          }
        });
        console.log('dynamicRulesMap', dynamicRulesMap);
      }

      // 最终进行主表单常规校验与动态校验结果合并
      instance.validate(
        (valid, done, fields) => {
          if (valid) {
            done();
            callback();
            console.log('校验成功');
          } else {
            done();
            console.log('校验失败', fields);
            if (this.validateShowFail) {
              this.msgError(this.validateFailText);
            }
          }
        },
        {
          mainFormRules,
          dynamicRulesMap
        }
      );
    },
    // 接口调用执行前钩子
    operateHookBefore(data) {
      try {
        if (this.feature && this.feature.hookBefore) {
          const anvilCodeStore = useAnvilCodeStore();
          // 获取当前表单实例
          const { instance } = anvilCodeStore.getPageForm(this.$attrs.pageId);
          return instance[this.feature.hookBefore](data);
        } else {
          return data;
        }
      } catch (e) {
        console.log('error!', e);
        return data;
      }
    },
    operateHookAfter(data) {
      try {
        if (this.feature && this.feature.hookAfter) {
          const anvilCodeStore = useAnvilCodeStore();
          // 获取当前表单实例
          const { instance } = anvilCodeStore.getPageForm(this.$attrs.pageId);
          return instance[this.feature.hookAfter](data);
        } else {
          return data;
        }
      } catch (e) {
        console.log('error!', e);
        return data;
      }
    },
    // 按钮功能
    btnFunc() {
      if (this.feature) {
        const { type } = this.feature;
        switch (type) {
          case 'link':
            this.handleLinkFunc(this.feature);
            break;
          case 'ajax':
            this.handleAjaxFunc(this.feature);
            break;
          case 'ajaxLocal':
            this.handleLocalAjaxFunc(this.feature);
            break;
          case 'ajaxModel':
            this.handleModelAjaxFunc(this.feature);
            break;
          case 'comp':
            this.handleCompCallFunc(this.feature);
            break;
          case 'wfStart':
            this.handleWfStart(this.feature);
            break;
        }
      }
    },
    handleLinkFunc(feature) {
      const { url, linkWay } = feature;
      if (linkWay == 'back') {
        this.$router.back();
      } else {
        let Query = {};
        // 解析出原本url中的path和query
        const RouteObj = this.$router.resolve(url);
        const { query, path } = RouteObj;
        // 获取传递参数
        const Param = getParamsWithMerge(this, feature);
        const from = encodeURIComponent(this.$route.fullPath);

        Query = {
          ...query,
          ...Param,
          from
        };

        console.log('路由跳转参数', Query);

        switch (linkWay) {
          case 'in':
            this.$router.push({ path, query: Query });
            break;
          case 'out':
            window.open(path + '?' + qs.stringify(Query));
            break;
          case 'postMsg':
            this.postIframeMsg('push', {
              path,
              query: Query
            });
            break;
          case 'postBack':
            this.postIframeMsg('back', {
              query: this.$route.query
            });
            break;
        }
      }
    },
    getAjaxObject(feature) {
      const anvilCodeStore = useAnvilCodeStore();
      const { type, url, download, isCallback, callback, showMsg, isFailCallback, failCallback } = feature;
      const finalData = getParamsWithMerge(this, feature);
      console.log('finalData', finalData);

      // 调用成功后的回调函数
      const callbackFunc = (res) => {
        if (showMsg) {
          ElMessage.success(res.msg);
        }

        if (isCallback && callback.length) {
          executeFunctionsInOrderByParamsSetting(this, this.operateHookAfter(res), callback);
        }
      };

      // 调用失败后的回调函数
      const failCallbackFunc = (error) => {
        if (isFailCallback && failCallback.length) {
          executeFunctionsInOrderByParamsSetting(this, undefined, failCallback);
        }
      };

      return { ...feature, params: this.operateHookBefore(finalData), headers: Headers, callback: callbackFunc, failCallback: failCallbackFunc, isDownload: download };
    },
    handleAjaxFunc(feature) {
      customApiExecute(this.getAjaxObject(feature), { noLoading: feature.noLoading });
    },
    handleModelAjaxFunc(feature) {
      modelApiExecute(this.getAjaxObject(feature), { noLoading: feature.noLoading });
    },
    handleLocalAjaxFunc(feature) {
      localApiExecute(this.getAjaxObject(feature), { noLoading: feature.noLoading });
    },
    handleCompCallFunc(feature) {
      if (feature.components.length) {
        executeFunctionsInOrderByParamsSetting(this, feature, feature.components, true);
      }
    },
    // 低代码页面作为iframe页面时需要向主页面传递消息
    postIframeMsg(type, params) {
      const { getSpaUniCode } = useAnvilCodeStore();
      const postObj = {
        type,
        params,
        pageId: getSpaUniCode
      };
      console.log('传递了msg', postObj);
      window.parent.postMessage(Base64.encode(JSON.stringify(postObj)), '*');
    },
    setVisible(val) {
      if ((typeof val == 'string' && val == 'true') || Boolean(val)) {
        this.btnShow = true;
      } else {
        this.btnShow = false;
      }
    },
    handleWfStart(feature) {
      const { wfCode, modelName, isSelectAssignee, completeFirst, isCallback, callback } = feature;
      let formData = getParamsWithMerge(this, feature);

      // 调用成功后的回调函数
      const callbackFunc = (res) => {
        if (res.code == '200') {
          this.msgSuccess('流程发起成功！');

          if (isCallback && callback.length) {
            executeFunctionsInOrderByParamsSetting(this, res, callback);
          }
        }
      };

      const businessKey = formData[feature.businessKey] ?? '';
      const businessSubject = modelName + '【' + businessKey + '】';
      formData = this.operateHookBefore(formData);

      // 分为多种情况处理
      // 是否需要选择处理人
      if (isSelectAssignee) {
        startWfInstanceAndSelectUser(this, wfCode, businessKey, modelName, businessSubject, completeFirst, formData, null, callbackFunc);
      } else {
        if (!modelName) {
          startWfInstanceWithoutModel({
            wfCode,
            businessKey,
            modelName,
            businessSubject,
            candidates: '',
            completeFirst,
            params: null,
            ...formData
          }).then((res) => {
            callbackFunc(res);
          });
        } else {
          startWfInstance({
            wfCode,
            businessKey,
            modelName,
            businessSubject,
            candidates: '',
            completeFirst,
            params: null,
            ...formData
          }).then((res) => {
            callbackFunc(res);
          });
        }
      }
    },
    open(dest) {
      this.selectUserParams = dest;
      this.showSelectUser = true;
    },
    doSelected(candidates) {
      const { completeFirst, isApprove, wfCode, businessKey, modelName, businessSubject, formData, callback } = this.selectUserParams;
      if (!modelName) {
        startWfInstanceWithoutModel({
          wfCode,
          businessKey,
          modelName,
          businessSubject,
          candidates,
          completeFirst,
          isApprove,
          params: null,
          ...formData
        }).then((res) => {
          callback(res);
        });
      } else {
        startWfInstance({
          wfCode,
          businessKey,
          modelName,
          businessSubject,
          candidates,
          completeFirst,
          isApprove,
          params: null,
          ...formData
        }).then((res) => {
          callback(res);
        });
      }
    }
  }
};
</script>
<style lang="scss" scoped>
.custom-btn {
  &-bg {
    background-color: var(--bgColor);
    border-color: var(--bdColor);
  }

  &-hover {
    &:hover {
      background-color: var(--hoverColor);
      border-color: var(--hoverColor);
    }
  }
}

.custom-btn-text {
  &-bg {
    color: var(--bgColor);
  }

  &-hover {
    &:hover {
      color: var(--hoverColor);
    }
  }
}

.custom-btn-icon {
  &-bg {
    fill: var(--bgColor);
  }

  &-hover {
    &:hover {
      fill: var(--hoverColor);
    }
  }
}

.confirm-content {
  display: flex;
  align-items: center;
  gap: 12px;
}
</style>
